Voyager —— 使用基于 LLM 驱动的 Agent 探索 Minecraft
· 阅读需 17 分钟
官方网址:https://voyager.minedojo.org/
用基于 LLM 的 Agent,通过“提问→求解→技能池”循环来不断探索游戏内容。和 SOTA 比,建造物品的数量是 3.3 倍、探索范围是 2.3 倍、解锁关键科技结点的速度是 15.3 倍。
关键概念
系统整体逻辑循环如下:
- Automatic Curriculum: Curriculum Agent —— 提出目标
- Iterative Prompting Mechanism: Action Agent —— 实现目标
- Self-Verification: Critic Agent —— 检查是否完成目标
- Skill Library: Skill Manager —— 技能库
使 用方式
from voyager import Voyager
azure_login = ...
openai_api_key = ...
voyager = Voyager(
azure_login=azure_login,
openai_api_key=openai_api_key,
)
# start lifelong learning
voyager.learn()
系统循环
https://github.com/MineDojo/Voyager/blob/01fb04666a8f3ba47dec74fb4cfd46e0125fe5a0/voyager/voyager.py
__init__
: 定义上述 3 个 Agent (Action, Curriculum, Critic),1 个 Manager (Skill Manager)
# init agents
self.action_agent = ActionAgent(
model_name=action_agent_model_name, # gpt-4
...
)
self.curriculum_agent = CurriculumAgent(
model_name=curriculum_agent_model_name, # gpt-4
temperature=curriculum_agent_temperature,
qa_model_name=curriculum_agent_qa_model_name, # gpt-3.5-turbo
qa_temperature=curriculum_agent_qa_temperature,
...
)
self.critic_agent = CriticAgent(
model_name=critic_agent_model_name, # gpt-4
...
)
self.skill_manager = SkillManager(
model_name=skill_manager_model_name, # gpt-3.5-turbo
temperature=skill_manager_temperature,
retrieval_top_k=skill_manager_retrieval_top_k,
...
)
learn
: 学习循环,提出任务 → 尝试完成任务 → 记录新技能
while True:
if self.recorder.iteration > self.max_iterations:
print("Iteration limit reached")
break
task, context = self.curriculum_agent.propose_next_task( # 提议下一个任务
events=self.last_events,
chest_observation=self.action_agent.render_chest_observation(),
max_retries=5,
)
...
try:
messages, reward, done, info = self.rollout( # 尝试完成任务
task=task,
context=context,
reset_env=reset_env,
)
except Exception as e:
...
if info["success"]:
self.skill_manager.add_new_skill(info) # 如果成功,则记录新技能
self.curriculum_agent.update_exploration_progress(info) # 更新探索进度
...
rollout
: 完成任务,准备完毕后最多尝试执行 N=4 次reset
: 准备工作- 使用 Skill Manager 获取与当前上下文匹配的技能信息,准备 Action Agent 的人设、提问等
step
: 执行一次完成任务的尝试- 调用 Action Agent 背后的 LLM 得到 bot 的指令代码
- 尝试使用 MC 插件运行代码,解析结果
- 调用 Critic Agent 背后的 LLM 检查任务是否完成
- 使用 Skill Manager 更新与当前上下文匹配的技能信息,准备 Action Agent 的人设、提问等
def rollout(self, *, task, context, reset_env=True):
self.reset(task=task, context=context, reset_env=reset_env) # 准备工作:获取技能信息、准备 Action Agent 的人设、提问等
while True:
messages, reward, done, info = self.step() # 尝试一次
if done:
break
return messages, reward, done, info
def reset(self, task, context="", reset_env=True):
...
skills = self.skill_manager.retrieve_skills(query=self.context) # 获取相关技能
...
# 生成 Action Agent 所需的系统设定和提问消息
system_message = self.action_agent.render_system_message(skills=skills)
human_message = self.action_agent.render_human_message(
events=events, code="", task=self.task, context=context, critique=""
)
self.messages = [system_message, human_message]
...
return self.messages
def step(self):
...
ai_message = self.action_agent.llm(self.messages) # Action Agent 生成代码
...
self.conversations.append(
(self.messages[0].content, self.messages[1].content, ai_message.content)
)
parsed_result = self.action_agent.process_ai_message(message=ai_message) # 处理生成的 js 代码
success = False
if isinstance(parsed_result, dict):
code = parsed_result["program_code"] + "\n" + parsed_result["exec_code"]
events = self.env.step( # 运行处理好的 js 代码
code,
programs=self.skill_manager.programs,
)
...
success, critique = self.critic_agent.check_task_success( # 检查任务是否完成
...
)
if self.reset_placed_if_failed and not success:
...
# 根据当前上下文重新检索技能
new_skills = self.skill_manager.retrieve_skills(
query=self.context
+ "\n\n"
+ self.action_agent.summarize_chatlog(events) # 从代码运行结果中手动提取事件
)
# 更新 Action Agent 的系统设定和提问信息
system_message = self.action_agent.render_system_message(skills=new_skills)
human_message = self.action_agent.render_human_message(
events=events,
code=parsed_result["program_code"],
task=self.task,
context=self.context,
critique=critique,
)
self.last_events = copy.deepcopy(events)
self.messages = [system_message, human_message]
else:
...
...
done = ( # 超过重试次数,算失败
self.action_agent_rollout_num_iter >= self.action_agent_task_max_retries
or success
)
...
return self.messages, 0, done, info